package com.bzkj.msfx.service.impl;


import com.alibaba.fastjson2.JSON;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.msfx.domain.BillsList;
import com.bzkj.msfx.domain.BillsMsfxDetail;
import com.bzkj.msfx.domain.warehouseXml.*;
import com.bzkj.msfx.mapper.MsfxWarehouseMapper;
import com.bzkj.msfx.service.WareHouseOutService;
import com.bzkj.msfx.utils.FusionHttpUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @projectName: btyy
 * @package: com.bzkj.btyy.service.impl
 * @className: WareHouseOutServiceImpl
 * @description: 出入库单服务层
 * @author: C1309
 * @createDate: 2024年02月19日
 * @version: v1.0
 */
@Service
public class WareHouseOutServiceImpl implements WareHouseOutService {

    @Resource
    private FusionHttpUtils fusionHttpUtils;

    @Resource
    private MsfxWarehouseMapper msfxWarehouseMapper;

    @Value("${pk_org.code}")
    private String entId;

    /**
     * 查询PDA出入库单据
     *
     * @param beginDate 开始时间
     * @param endDate   结束时间
     * @param flag      单据状态
     * @param userId    用户ID
     * @param billsId   单据ID
     * @return 查询结果
     */
    @Override
    public AjaxResult queryBillsList(String beginDate, String endDate,
                                     String flag, String userId, String billsId,
                                     String billsType) {
        if (Objects.equals(endDate, "")) {
            endDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        }
        if (Objects.equals(beginDate, "")) {
            // 获取当前日期
            LocalDate currentDate = LocalDate.now();

            // 往前推三天
            LocalDate threeDaysBefore = currentDate.minusDays(3);
            // 格式化输出日期（可选）
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            beginDate = threeDaysBefore.format(formatter);
        }
        beginDate = beginDate + " 00:00:00";
        endDate = endDate + " 23:59:59";
        ArrayList<BillsList> relationLists = msfxWarehouseMapper.selectBillsList(beginDate, endDate, flag, entId, billsId, userId, billsType);
        return AjaxResult.success(relationLists);
    }

    /**
     * 查询PDA出入库单据详情
     *
     * @param billsId 单据编号
     * @return 查询结果
     */
    @Override
    public AjaxResult queryBillsDetailList(String billsId) {
        ArrayList<BillsMsfxDetail> billsMsfxDetails = msfxWarehouseMapper.selectBillsDetailList(billsId);
        return AjaxResult.success(billsMsfxDetails);
    }

    /**
     * 查询工厂列表
     *
     * @return 查询结果
     */
    @Override
    public AjaxResult queryFactoryList() {

        return null;
    }

    /**
     * 查询PDA出入库单据详情(生成xml用）
     *
     * @param billsIds 单据编号
     * @return 查询结果
     */
    @Override
    public AjaxResult billsToXml(List<String> billsIds) {
        ExecutorService executor = Executors.newFixedThreadPool(12);
        ArrayList<HashMap<String, String>> resultList = new ArrayList<>();


        // 使用同步锁确保对resultList的安全访问
        synchronized (resultList) {
            if (!billsIds.isEmpty()) {
                for (String billsId : billsIds) {
                    executor.execute(() -> {
                        HashMap<String, String> resultMap = new HashMap<>();
                        ArrayList<WarehouseXmlDetail> billsDetailList = msfxWarehouseMapper.selectBillsDetailListXml(billsId, entId);
                        if (!billsDetailList.isEmpty()) {
                            HashMap<String, Object> data = getData(billsDetailList);

                            WarehouseDataField dataField = new WarehouseDataField();
                            @SuppressWarnings("unchecked")
                            ArrayList<WarehouseData> dataList = (ArrayList<WarehouseData>) data.get("dataList");
                            dataField.setDataList(dataList);

                            ArrayList<WarehouseMetaData> metaDataList = getMetaData();
                            WarehouseDataMaping dataMaping = new WarehouseDataMaping();
                            dataMaping.setMetaDataList(metaDataList);
                            WarehouseAction action = new WarehouseAction();
                            if (data.get("billsType").toString().endsWith("WareHouseOut")) {
                                action = getActionDataList("WareHouseOut");
                            } else if (data.get("billsType").toString().endsWith("WareHouseIn")) {
                                action = getActionDataList("WareHouseIn");
                            }
                            WarehouseActionMaping actionMaping = new WarehouseActionMaping();
                            actionMaping.setAction(action);

                            WarehouseEvent event = new WarehouseEvent();
                            event.setWarehouseActionMaping(actionMaping);
                            event.setWarehouseDataMaping(dataMaping);
                            event.setWarehouseDataField(dataField);
                            if (data.get("billsType").toString().endsWith("WareHouseOut")) {
                                event.setMainAction("WareHouseOut");
                                event.setName(data.get("billsType").toString());
                            } else if (data.get("billsType").toString().endsWith("WareHouseIn")) {
                                event.setMainAction("WareHouseIn");
                                event.setName(data.get("billsType").toString());
                            }

                            WarehouseEvents Events = new WarehouseEvents();
                            Events.setEvent(event);

                            WarehouseDocument document = new WarehouseDocument();
                            document.setWarehouseEvents(Events);

                            try {
                                XmlMapper xmlMapper = new XmlMapper();
                                String xmlInfo = xmlMapper.writeValueAsString(document);
                                String jsonInfo = billsId;
                                if (Objects.equals(data.get("error").toString(), "1")) {
                                    if (!Objects.equals(data.get("billsType").toString(), "CheckWareHouseOut")) {
                                        jsonInfo = billsId + "(请添加往来单位)";
                                    }

                                }
                                resultMap.put(jsonInfo, xmlInfo);
                                // 在同步块内部添加元素到resultList
                                synchronized (resultList) {
                                    resultList.add(resultMap);
                                }
                                msfxWarehouseMapper.updateBillsFlag(billsId);
                            } catch (JsonProcessingException e) {
//                                log.error("单据号为：" + billsId + "在生成xml文件时发生异常！异常原因为：" + e.getMessage(), e);
                                resultMap.put(billsId, "异常原因为：" + e.getMessage() + ",请联系系统管理员处理！");
                                // 在同步块内部添加元素到resultList
                                synchronized (resultList) {
                                    resultList.add(resultMap);
                                }
                            }
                        } else {
                            resultMap.put(billsId, "异常原因为：该单据无追溯数据!");
                            // 在同步块内部添加元素到resultList
                            synchronized (resultList) {
                                resultList.add(resultMap);
                            }
                        }
                    });
                }
            }
        }
        // 等待所有任务完成
        executor.shutdown();
        try {
            // 等待所有任务完成，最多等待5分钟
            if (!executor.awaitTermination(5, TimeUnit.MINUTES)) {
                // 如果超时，则输出提示信息
                throw new RuntimeException("等待超时，仍有未完成任务");
            }
        } catch (InterruptedException e) {
            // 如果等待过程中被中断，则输出异常信息
            e.printStackTrace();
        }
        return AjaxResult.success(resultList);
    }


    /**
     * 删除订单
     *
     * @param billsId       订单id
     * @param businessEntId 工厂id
     * @return 删除结果
     */
    @Override
    public AjaxResult redoBills(String billsId, String businessEntId) {
        try {
            return fusionHttpUtils.sendDeleteRequest("/wareHouse/redo/" + billsId + "/" + businessEntId, null, null, null);
        } catch (Exception e) {
            return AjaxResult.error("删除订单失败，具体原因：" + e.getMessage());
        }
    }

    /**
     * 查询用户列表
     *
     * @param typeId 查询类型（如果typeId为1查询全部，如果typeId为部门Id查询该部门下的用户）
     * @return 查询结果
     */
    @Override
    public AjaxResult getUserList(String typeId) {
        try {
            return fusionHttpUtils.sendGet("/wareHouse/user", null);
        } catch (RuntimeException e) {
            return AjaxResult.error("查询用户列表失败，具体原因：" + e.getMessage());
        }
    }

    /**
     * 追溯码替换
     *
     * @param params 请求参数
     * @return 替换结果
     */
    @Override
    public AjaxResult changeCode(Map<String, String> params) {
        try {
            return fusionHttpUtils.sendPostRequest("/wareHouse/changeCode", null, JSON.toJSONString(params), "application/json");
        } catch (Exception e) {
            return AjaxResult.error("追溯码替换失败，具体原因：" + e.getMessage());
        }
    }

    /**
     * 删除订单
     *
     * @param billsId       订单id
     * @param businessEntId 用户名
     * @return 删除结果
     */
    @Override
    public AjaxResult delBillsId(String billsId, String businessEntId) {

        return null;
    }

    /**
     * 组装出入库单据
     *
     * @param billsDetailList 单据明细列表
     * @return 组装完成的单据信息
     */
    private static HashMap<String, Object> getData(ArrayList<WarehouseXmlDetail> billsDetailList) {
        HashMap<String, Object> resultMap = new HashMap<>(3);
        ArrayList<WarehouseData> dataList = new ArrayList<>();
        String billsType = "";
        for (WarehouseXmlDetail xmlDetail : billsDetailList) {
            WarehouseData data = new WarehouseData();
            data.setActor(xmlDetail.getUserId());
            data.setCode(xmlDetail.getBarCode());
            data.setFromPerson(xmlDetail.getUserId());
            data.setActDate(xmlDetail.getScanTime());
            if (xmlDetail.getCustomerId() == null || xmlDetail.getCustomerId().isEmpty()) {
                resultMap.put("error", "1");
            } else {
                data.setToCorpId(xmlDetail.getCustomerId());
                resultMap.put("error", "0");
            }
            data.setCorpOrderId(xmlDetail.getCorpOrderId());
            data.setDisCorpId(xmlDetail.getSenderId());
            billsType = xmlDetail.getBillsWareType();
            dataList.add(data);
        }
        resultMap.put("dataList", dataList);
        resultMap.put("billsType", billsType);
        return resultMap;
    }

    /**
     * 构建MetaData节点
     *
     * @return MetaData节点
     */
    @NotNull
    private static ArrayList<WarehouseMetaData> getMetaData() {
        ArrayList<WarehouseMetaData> metaDataList = new ArrayList<>();
        WarehouseMetaData metaData1 = new WarehouseMetaData();
        metaData1.setName("CorpOrderID");
        metaData1.setType("String");
        metaDataList.add(metaData1);

        WarehouseMetaData metaData2 = new WarehouseMetaData();
        metaData2.setName("Actor");
        metaData2.setType("String");
        metaDataList.add(metaData2);

        WarehouseMetaData metaData3 = new WarehouseMetaData();
        metaData3.setName("ActDate");
        metaData3.setType("Date");
        metaDataList.add(metaData3);

        WarehouseMetaData metaData4 = new WarehouseMetaData();
        metaData4.setName("ToCorpID");
        metaData4.setType("String");
        metaDataList.add(metaData4);

        WarehouseMetaData metaData5 = new WarehouseMetaData();
        metaData5.setName("Code");
        metaData5.setType("String");
        metaDataList.add(metaData5);

        return metaDataList;
    }

    /**
     * 组装Action节点
     *
     * @param billsType 单据类型
     * @return Action节点
     */
    @NotNull
    private static WarehouseAction getActionDataList(String billsType) {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("CorpOrderID");
        arrayList.add("Actor");
        arrayList.add("ToCorpID");
        arrayList.add("ActDate");
        arrayList.add("Code");

        WarehouseAction action = new WarehouseAction();
        action.setName(billsType);
        action.setActionData(arrayList);
        return action;
    }
}
